package com.ruoyi.common.service.impl;

import com.ruoyi.common.exception.ErrorCodeEnum;
import com.ruoyi.common.utils.CommonUtil;
import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;

/**
 * 操作消息提醒
 *
 * @author jorchi
 */
@Component
public class ResultMsg extends HashMap<String, Object> {
    private static final Logger log = LoggerFactory.getLogger(ResultMsg.class);
    private static final long serialVersionUID = 1L;

    public static final String CODE_TAG = "code";
    public static final String MSG_TAG = "msg";
    public static final String serverVersion = "sVersion";
    public static final String DATA_TAG = "data";
    public static final String TOTAL = "total";
    public static final String ATTACH = "attach";

    /**
     * 状态类型
     */
    public enum Type {
        /**
         * 成功
         */
        SUCCESS(200),
        /**
         * 客户端逻辑错误
         */
        CLIENT_ERROR(400),
        /**
         * 警告
         */
        WARN(403),
        /** 无权 */

        /**
         * 错误
         */
        ERROR(500);
        private final int value;

        Type(int value) {
            this.value = value;
        }

        public int value() {
            return this.value;
        }
    }

    /**
     * 状态类型
     */
    private Type type;

    /**
     * 初始化一个新创建的 AjaxResult 对象，使其表示一个空消息。
     */
    public ResultMsg() {
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     *
     * @param type 状态类型
     * @param msg  返回内容
     */
    public ResultMsg(Type type, String msg) {
        super.put(CODE_TAG, type.value);
        super.put(MSG_TAG, msg);
        this.type = type;
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     *
     * @param type 状态类型
     * @param msg  返回内容
     * @param data 数据对象
     */
    public ResultMsg(Type type, String msg, Object data) {
        super.put(CODE_TAG, type.value);
        super.put(MSG_TAG, msg);
        if (StringUtils.isNotNull(data)) {
            super.put(DATA_TAG, data);
        }
        this.type = type;
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     */
    public static ResultMsg of(Integer code, String... msg) {
        ResultMsg resultMsg = new ResultMsg();
        resultMsg.put(CODE_TAG, code);
        resultMsg.put(MSG_TAG, CommonUtil.append(msg));
        return resultMsg;
    }

    /**
     * 返回成功消息
     *
     * @return 成功消息
     */
    public static ResultMsg success() {
        return ResultMsg.success("操作成功");
    }

    /**
     * 返回成功数据
     *
     * @return 成功消息
     */
    public static ResultMsg success(Object data) {
        return ResultMsg.success("操作成功", data);
    }

    /**
     * 返回成功消息
     *
     * @param msg 返回内容
     * @return 成功消息
     */
    public static ResultMsg success(String msg) {
        return ResultMsg.success(msg, null);
    }

    /**
     * 返回成功消息
     *
     * @param msg  返回内容
     * @param data 数据对象
     * @return 成功消息
     */
    public static ResultMsg success(String msg, Object data) {
        return new ResultMsg(Type.SUCCESS, msg, data);
    }

    /**
     * 返回警告消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */
    public static ResultMsg warn(String msg) {
        return ResultMsg.warn(msg, null);
    }

    /**
     * 返回警告消息
     *
     * @param msg  返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static ResultMsg warn(String msg, Object data) {
        return new ResultMsg(Type.WARN, msg, data);
    }

    /**
     * 返回错误消息
     *
     * @return
     */
    public static ResultMsg error() {
        return ResultMsg.error("操作失败");
    }

    /**
     * 返回错误消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */
    public static ResultMsg error(String msg) {
        log.warn(CommonUtil.append(CommonUtil.whoCalledMe(), " errorCode:500, message:", msg));
        return ResultMsg.error(msg, null);
    }

    /**
     * 返回错误消息
     *
     * @param msg  返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static ResultMsg error(String msg, Object data) {
        return new ResultMsg(Type.ERROR, msg, data);
    }

    public static ResultMsg clientError(String msg) {
        log.error(CommonUtil.append(CommonUtil.whoCalledMe(), msg));
        return new ResultMsg(Type.CLIENT_ERROR, msg, null);
    }

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    public int getCode() {
        return (int) super.getOrDefault(CODE_TAG, 0);
    }

    public void setCode(int code) {
        super.put(CODE_TAG, code);
    }

    public String getMsg() {
        return (String) super.getOrDefault(MSG_TAG, null);
    }

    public void setMsg(String msg) {
        super.put(MSG_TAG, msg);
    }

    public Object getData() {
        return super.getOrDefault(DATA_TAG, null);
    }

    public void setData(Object data) {
        if (StringUtils.isNotNull(data)) {
            super.put(DATA_TAG, data);
        }
    }

    /**
     * 总数
     */
    private Integer total;
    /**
     * 额外数据
     */
    private Object attach;

    public static ResultMsg ok() {
        return new ResultMsg(ErrorCodeEnum.CommonErr.OK);
    }

    public static ResultMsg ok(String msg) {
        return new ResultMsg(ErrorCodeEnum.CommonErr.OK, msg);
    }

    public static ResultMsg ok(Object data) {
        return new ResultMsg(ErrorCodeEnum.CommonErr.OK, data);
    }

    public static ResultMsg fail() {
        log.error(CommonUtil.append(CommonUtil.whoCalledMe(), " fail, errorCode:500!!"));
        return new ResultMsg(ErrorCodeEnum.CommonErr.ERROR);
    }

    public static ResultMsg fail(ErrorCodeEnum.CommonErr err) {
        log.warn(CommonUtil.append(CommonUtil.whoCalledMe(), " errorCode:500, message:", err.message()));
        return new ResultMsg(err);
    }

    public static ResultMsg fail(Object data) {
        log.error(CommonUtil.append(CommonUtil.whoCalledMe(), " fail, errorCode:500!!"));
        return new ResultMsg(ErrorCodeEnum.CommonErr.ERROR, data);
    }

    public static ResultMsg fail(String msg) {
        log.warn(CommonUtil.append(CommonUtil.whoCalledMe(), " errorCode:500, message:", msg));
        return new ResultMsg(ErrorCodeEnum.CommonErr.ERROR, msg);
    }

    public static ResultMsg ok(Object data, int total) {
        return new ResultMsg(ErrorCodeEnum.CommonErr.OK, data, total);
    }

    public static ResultMsg ok(Object data, Integer total, Object attach) {
        return new ResultMsg(data, ErrorCodeEnum.CommonErr.OK, total, attach);
    }

    public static ResultMsg ok(ErrorCodeEnum.CommonErr ok) {
        return new ResultMsg(ok);
    }

    public ResultMsg(ErrorCodeEnum.CommonErr em) {
        super.put(CODE_TAG, em.code());
        super.put(MSG_TAG, em.message());
    }

    public ResultMsg(ErrorCodeEnum.CommonErr em, String msg) {
        super.put(CODE_TAG, em.code());
        super.put(MSG_TAG, msg);
    }

    public ResultMsg(ErrorCodeEnum.CommonErr em, Object data) {
        super.put(CODE_TAG, em.code());
        super.put(MSG_TAG, em.message());
        if (StringUtils.isNotNull(data)) {
            super.put(DATA_TAG, data);
        }
    }

    public ResultMsg(ErrorCodeEnum.CommonErr em, Object data, int total) {
        super.put(CODE_TAG, em.code());
        super.put(MSG_TAG, em.message());
        if (StringUtils.isNotNull(data)) {
            super.put(DATA_TAG, data);
        }
        super.put(TOTAL, total);
    }

    public ResultMsg(Object data, ErrorCodeEnum.CommonErr em, Integer total, Object attach) {
        super.put(CODE_TAG, em.code());
        super.put(MSG_TAG, em.message());
        if (StringUtils.isNotNull(data)) {
            super.put(DATA_TAG, data);
        }
        super.put(TOTAL, total);
        super.put(ATTACH, attach);
    }

    public boolean isSuccess() {
        return ErrorCodeEnum.CommonErr.OK.code() == getCode();
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
                .append("code", getCode())
                .append("msg", getMsg())
                .append("data", getData())
                .toString();
    }
}